<?php

namespace app\common\plugin;

use Webman\Route;

/**
 * 插件路由管理器
 * 自动注册插件路由，支持PSR-4规范
 */
class PluginRouteManager
{
    /**
     * 注册所有启用插件的路由
     */
    public static function registerPluginRoutes()
    {
        $enabled_plugins = get_enabled_plugins();

        foreach ($enabled_plugins as $plugin_name) {
            static::registerPluginRoute($plugin_name);
        }
    }

    /**
     * 注册单个插件的路由
     * @param string $plugin_name 插件名称
     */
    public static function registerPluginRoute($plugin_name)
    {
        $plugin_path     = get_plugin_path($plugin_name);
        $controller_path = $plugin_path . '/controller';

        // 检查插件是否有控制器目录
        if (is_dir($controller_path)) {
            // 先扫描并注册控制器文件（具体路由）
            $controllers = static::scanControllers($controller_path);
            foreach ($controllers as $controller_info) {
                static::registerControllerRoutes($plugin_name, $controller_info);
            }
        }

        // 最后注册插件静态文件路由（通配符路由）
        static::registerPluginStaticRoute($plugin_name);
    }

    /**
     * 扫描控制器文件
     * @param string $controller_path 控制器目录路径
     * @param string $namespace_prefix 命名空间前缀
     * @return array
     */
    protected static function scanControllers($controller_path, $namespace_prefix = '')
    {
        $controllers = [];
        $files       = scandir($controller_path);

        foreach ($files as $file) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            $file_path = $controller_path . '/' . $file;

            if (is_dir($file_path)) {
                // 递归扫描子目录
                $sub_controllers = static::scanControllers($file_path, $namespace_prefix . $file . '\\');
                $controllers     = array_merge($controllers, $sub_controllers);
            } elseif (pathinfo($file, PATHINFO_EXTENSION) === 'php') {
                // PHP控制器文件
                $controller_name = pathinfo($file, PATHINFO_FILENAME);
                $controllers[]   = [
                    'name'      => $controller_name,
                    'namespace' => $namespace_prefix,
                    'file'      => $file_path
                ];
            }
        }

        return $controllers;
    }

    /**
     * 注册控制器路由
     * @param string $plugin_name 插件名称
     * @param array $controller_info 控制器信息
     */
    protected static function registerControllerRoutes($plugin_name, $controller_info)
    {
        $controller_name = $controller_info['name'];
        $namespace       = $controller_info['namespace'];

        // 构建完整的类名
        $class_name = "plugins\\{$plugin_name}\\controller\\{$namespace}{$controller_name}";

        // 检查类是否存在
        if (!class_exists($class_name)) {
            return;
        }

        // 获取类的所有公共方法
        $reflection = new \ReflectionClass($class_name);
        $methods    = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);

        foreach ($methods as $method) {
            // 跳过魔术方法和继承的方法
            if (strpos($method->getName(), '__') === 0 || $method->getDeclaringClass()->getName() !== $class_name) {
                continue;
            }

            $action = $method->getName();

            // 构建路由路径
            $route_path = static::buildRoutePath($plugin_name, $controller_name, $namespace, $action);

            // 注册GET和POST路由，避免与OPTIONS通配符冲突
            Route::get($route_path, [$class_name, $action]);
            Route::post($route_path, [$class_name, $action]);

            // 如果是index方法，也注册不带action的路由
            if ($action === 'index') {
                $base_path = str_replace('/index', '', $route_path);
                Route::get($base_path, [$class_name, $action]);
                Route::post($base_path, [$class_name, $action]);
            }
        }
    }

    /**
     * 构建路由路径
     * @param string $plugin_name 插件名称
     * @param string $controller_name 控制器名称
     * @param string $namespace 命名空间
     * @param string $action 方法名
     * @return string
     */
    protected static function buildRoutePath($plugin_name, $controller_name, $namespace, $action)
    {
        // 转换为小写并用连字符分隔
        $plugin_slug     = strtolower($plugin_name);
        $controller_slug = strtolower(preg_replace('/([A-Z])/', '-$1', $controller_name));
        $controller_slug = trim($controller_slug, '-');

        // 处理命名空间
        $namespace_path = '';
        if ($namespace) {
            $namespace_parts = explode('\\', trim($namespace, '\\'));
            $namespace_path  = '/' . implode('/', array_map('strtolower', $namespace_parts));
        }

        // 构建完整路径
        return "/plugins/{$plugin_slug}{$namespace_path}/{$controller_slug}/{$action}";
    }

    /**
     * 注册插件静态文件路由
     * @param string $plugin_name 插件名称
     */
    protected static function registerPluginStaticRoute($plugin_name)
    {
        $plugin_slug = strtolower($plugin_name);

        // 注册静态文件路由，使用通配符匹配所有静态文件
        Route::get("/plugins/{$plugin_slug}/{path:.+}", function ($path) use ($plugin_name) {
            // 检查是否是静态文件（有文件扩展名）
            $extension        = pathinfo($path, PATHINFO_EXTENSION);
            $staticExtensions = [
                'css',
                'js',
                'png',
                'jpg',
                'jpeg',
                'gif',
                'svg',
                'ico',
                'woff',
                'woff2',
                'ttf',
                'eot',
                'otf',
                'mp3',
                'mp4',
                'avi',
                'mov',
                'pdf',
                'zip',
                'rar',
                'txt',
                'xml',
                'json',
                'html',
                'htm'
            ];

            if (!in_array(strtolower($extension), $staticExtensions)) {
                // 不是静态文件，返回false让其他路由处理
                return false;
            }

            // 构建实际文件路径
            $plugin_path = get_plugin_path($plugin_name);
            $public_path = $plugin_path . '/public';
            $real_file   = $public_path . '/' . $path;

            // 检查文件是否存在
            if (!is_file($real_file)) {
                return new \Webman\Http\Response(404, [], 'Static file not found');
            }

            // 清除文件状态缓存
            clearstatcache(true, $real_file);
            if (!is_file($real_file)) {
                return new \Webman\Http\Response(404, [], 'Static file not found');
            }

            // 返回文件
            return (new \Webman\Http\Response())->file($real_file);
        });
    }
}
